<script lang="ts" setup>
/** 上传单个图片组件
 * v-model:imageIds 图片文件ids
 * width 上传框宽度
 * height 上传框高度
 * defaultFileList 已上传文件列表
 * max 限制文件上传数量，不传则为无限制
 * round 上传展示图片是否圆角
*/
import type { UploadFileInfo } from 'naive-ui'
import type { FileItemModel } from '@/api/file'
import { getToken } from '@/utils/auth/token'

interface Props {
  imageIds: string
  width?: string
  height?: string
  max?: number | undefined
  defaultFileList?: FileItemModel[]
  round?: boolean
}
const props = withDefaults(defineProps<Props>(), {
  imageIds: '',
  width: '100px',
  height: '100px',
  max: undefined,
  round: false,
  defaultFileList: () => [],
})
const emit = defineEmits(['update:imageIds'])

const { width, height, max, round } = toRefs(props)

// 上传预览图片边框处理 方 or 圆
enum BorderRadiusSelect {
  round = '48px',
  square = '6px',
}
const borderRadius = ref<BorderRadiusSelect>(BorderRadiusSelect.square)
watch(() => round.value, (newVal: boolean) => {
  console.log(newVal, 'newVal')
  borderRadius.value = newVal ? BorderRadiusSelect.round : BorderRadiusSelect.square
}, { immediate: true })

// 文件id双向绑定
const fileIds = computed({
  get() {
    return props.imageIds
  },
  set(newVal) {
    emit('update:imageIds', newVal)
  },
})

// 已上传文件列表数据
const fileList = ref<UploadFileInfo[]>([])
watch(() => props.defaultFileList, (newVal) => {
  fileList.value = newVal.map((item) => {
    const itemData: UploadFileInfo = {
      id: item.id as string,
      name: item.name,
      status: 'finished',
      url: item.url,
    }
    return itemData
  })
}, { immediate: true })

// 上传地址 && token
const headers = ref({ token: getToken() })
const action = ref(`${import.meta.env.VITE_BASE_API}/fileHandle/uploadImage`)

function onFinish({ file, event }: { // 上传完成回调
  file: UploadFileInfo
  event?: any
}) {
  const index = fileList.value.findIndex(item => item.id === file.id) // 获取当前上传索引
  const { code, msg, data }: { code: number; msg: string; data: FileItemModel } = JSON.parse(event.target.response as string)
  if (code === 0) {
    window.$message?.success(msg)

    fileList.value[index].id = data.id.toString() // 组件提示不要修改id，暂时无法找到其他替代方案，只能修改
    fileList.value[index].status = 'finished'
    fileIds.value = fileList.value.map(item => item.id).toString()
  }
  else { // 接口定义上传失败
    window.$message?.error(msg)
    file.status = 'error'
    fileIds.value = ''
  }
}
function onError() { // 上传失败回调
  window.$message?.error('上传失败，请重新上传')
  fileList.value = []
  fileIds.value = fileList.value.map(item => item.id).toString()
}
function onRemove() { // 删除文件回调
  fileList.value = []
  fileIds.value = fileList.value.map(item => item.id).toString()
}
</script>

<template>
  <n-upload
    v-model:file-list="fileList"
    :action="action"
    :headers="headers"
    :max="max"
    :multiple="max === 1 ? false : true"
    accept="image/*"
    list-type="image-card"
    :on-error="onError"
    :on-finish="onFinish"
    :on-remove="onRemove"
    class="CuploadImage"
  >
    点击上传
  </n-upload>
</template>

<style lang="scss" scoped>
.CuploadImage :deep(.n-upload-file-list.n-upload-file-list--grid) {
  grid-template-columns: repeat(auto-fill, v-bind(width))
}
.CuploadImage :deep(.n-upload-trigger.n-upload-trigger--image-card) {
  width: v-bind(width);
  height: v-bind(height);
}
:deep(.n-upload-dragger) {
  border-radius: v-bind(borderRadius) !important;
}
.CuploadImage :deep(.n-upload-file-list .n-upload-file.n-upload-file--image-card-type) {
  width: v-bind(width) !important;
  height: v-bind(height) !important;
  border-radius: v-bind(borderRadius) !important;
}
.CuploadImage :deep(.n-upload-file-info .n-image) {
  width: 100%;
  height: 100%;
}
.CuploadImage :deep(.n-upload-file-info__thumbnail img) {
  object-fit: cover !important;
}
</style>
